using System;
using System.Collections.Generic;
using System.Linq;

namespace ServiceModel.Syndication.LEAP2A {
    internal static class LeapNamespaces {
        public const string Rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
        public const string AtomThreading = "http://purl.org/syndication/thread/1.0";
    }

    public enum LeapPredicates {
        AtomRelated,
        AtomRelatedBy,
        LeapRelation,
        LeapRelationOf,
        IsEvidenceOf,
        HasEvidence,
        IsPartOf,
        HasPart,
        Supports,
        SupportedBy,
        IsOutcomeOf,
        HasOutcome,
        ReferencedBy,
        References,
        Attends,
        AttendedBy,
        ReflectsOn,
        ReflectedOnBy,
        HasAgenda,
        IsAgendaOf,
        Custom,
    }

    public enum LeapTypes {
        Activity,
        Meeting,
        Person,
        Ability,
        Achievement,
        Selection,
        Plan,
        Organization,
        Entry,
        Resource,
        Affiliation,
        Custom
    }

    public static class NamespaceFixer {
        /// <summary>
        /// Attempts to fix the specified requested namespace.
        /// </summary>
        /// <param name="requestedNamespace">The requested namespace.</param>
        /// <returns></returns>
        public static string Fix(string requestedNamespace) {
            List<string> namespaces = new List<string>();
            namespaces.AddRange(LeapPredicateValues.Namespaces.Values);
            namespaces.AddRange(LeapCategorySchemes.Namespaces.Values);
            namespaces.AddRange(LeapTypeValues.Namespaces.Values);
            namespaces.Add(LeapNamespaces.AtomThreading);
            namespaces.Add(LeapNamespaces.Rdf);

            foreach (var ns in namespaces) {
                if (ns.ToLower().StartsWith(requestedNamespace.ToLower())) {
                    return ns;
                }
            }

            return requestedNamespace;
        }
    }

    /// <summary>
    /// Link types included in LEAP2A, 
    /// details can be found at http://wiki.cetis.ac.uk/2009-03/LEAP2A_predicates
    /// </summary>
    public static class LeapPredicateValues {
        public static readonly Dictionary<LeapVersion, string> Namespaces;
        public static readonly Dictionary<LeapVersion, string> NamespacePrefixes;

        private static Dictionary<LeapPredicates, string> predicateLookup;

        private const string Namespace = "http://terms.leapspecs.org/";
        private const string NamespacePrefix = "leap2";

        static LeapPredicateValues() {
            Namespaces = new Dictionary<LeapVersion, string>();
            Namespaces.Add(LeapVersion.v2009_03, "http://wiki.cetis.ac.uk/2009-03/LEAP2A_predicates#"); 
            Namespaces.Add(LeapVersion.v2010_07, Namespace); 
            Namespaces.Add(LeapVersion.Development, Namespace);

            NamespacePrefixes = new Dictionary<LeapVersion, string>();
            NamespacePrefixes.Add(LeapVersion.v2009_03, "leap");
            NamespacePrefixes.Add(LeapVersion.v2010_07, NamespacePrefix);
            NamespacePrefixes.Add(LeapVersion.Development, NamespacePrefix); 

            predicateLookup = new Dictionary<LeapPredicates, string>();
            predicateLookup.Add(LeapPredicates.AtomRelated, "related");
            predicateLookup.Add(LeapPredicates.AtomRelatedBy, "related_by");
            predicateLookup.Add(LeapPredicates.LeapRelation, "relation");
            predicateLookup.Add(LeapPredicates.LeapRelationOf, "relation_of");
            predicateLookup.Add(LeapPredicates.IsEvidenceOf, "is_evidence_of");
            predicateLookup.Add(LeapPredicates.HasEvidence, "has_evidence");
            predicateLookup.Add(LeapPredicates.IsPartOf, "is_part_of");
            predicateLookup.Add(LeapPredicates.HasPart, "has_part");
            predicateLookup.Add(LeapPredicates.Supports, "supports");
            predicateLookup.Add(LeapPredicates.SupportedBy, "supported_by");
            predicateLookup.Add(LeapPredicates.IsOutcomeOf, "is_outcome_of");
            predicateLookup.Add(LeapPredicates.HasOutcome, "has_outcome");
            predicateLookup.Add(LeapPredicates.ReferencedBy, "referenced_by");
            predicateLookup.Add(LeapPredicates.References, "references");
            predicateLookup.Add(LeapPredicates.Attends, "attends");
            predicateLookup.Add(LeapPredicates.AttendedBy, "attended_by");
            predicateLookup.Add(LeapPredicates.ReflectsOn, "reflects_on");
            predicateLookup.Add(LeapPredicates.ReflectedOnBy, "reflected_on_by");
            predicateLookup.Add(LeapPredicates.HasAgenda, "has_agenda");
            predicateLookup.Add(LeapPredicates.IsAgendaOf, "is_agenda_of");
        }

        public static bool ContainsNamespace(string value) {
            if (string.IsNullOrEmpty(value)) {
                return false;
            }

            foreach (var ns in Namespaces) {
                if (ns.Value.ToLower() == value.ToLower()) {
                    return true;
                }
            }

            return false;
        }

        public static string CurieFor(LeapPredicates link, LeapFeed feed) {
            if (link == LeapPredicates.AtomRelated || link == LeapPredicates.AtomRelatedBy){
                return predicateLookup[link];
            }

            return feed.LeapPredicatesNamespacePrefix + ":" + predicateLookup[link];
        }

        public static string UrlFor(LeapPredicates link, LeapFeed feed) {
            if (link == LeapPredicates.AtomRelated || link == LeapPredicates.AtomRelatedBy) {
                return predicateLookup[link];
            }

            return feed.LeapPredicatesNamespace + predicateLookup[link];
        }

        public static LeapPredicates FromUrl(string relationshipType, LeapFeed feed) {
            if (string.IsNullOrEmpty(relationshipType)) {
                return LeapPredicates.Custom;
            }

            var type = feed.UriFromCurie(relationshipType).Replace(feed.LeapPredicatesNamespace, "");

            try {
                return predicateLookup.First(p => p.Value == type).Key;
            } catch {
                return LeapPredicates.Custom;
            }
        }
    }

    /// <summary>
    /// Class types included in LEAP2A, 
    /// details can be found at http://wiki.cetis.ac.uk/2009-03/LEAP2A_types
    /// </summary>
    public static class LeapTypeValues {
        public static readonly Dictionary<LeapVersion, string> Namespaces;
        public static readonly Dictionary<LeapVersion, string> NamespacePrefixes;

        private const string Namespace = "http://terms.leapspecs.org/";
        private const string NamespacePrefix = "leap2";

        static LeapTypeValues() {
            Namespaces = new Dictionary<LeapVersion, string>();
            Namespaces.Add(LeapVersion.v2009_03, "http://wiki.cetis.ac.uk/2009-03/LEAP2A_types#"); 
            Namespaces.Add(LeapVersion.v2010_07, Namespace); 
            Namespaces.Add(LeapVersion.Development, Namespace);

            NamespacePrefixes = new Dictionary<LeapVersion, string>();
            NamespacePrefixes.Add(LeapVersion.v2009_03, "leaptype");
            NamespacePrefixes.Add(LeapVersion.v2010_07, NamespacePrefix);
            NamespacePrefixes.Add(LeapVersion.Development, NamespacePrefix);
        }

        public static bool ContainsNamespace(string value) {
            if (string.IsNullOrEmpty(value)) {
                return false;
            }

            foreach (var ns in Namespaces) {
                if (ns.Value.ToLower() == value.ToLower()) {
                    return true;
                }
            }

            return false;
        }

        public static LeapTypes FromUrl(string itemType, LeapFeed feed) {
            if (string.IsNullOrEmpty(itemType)){
                return LeapTypes.Entry;
            }

            var type = feed.UriFromCurie(itemType).Replace(feed.LeapTypesNamespace, "");

            try {
                return (LeapTypes)Enum.Parse(typeof(LeapTypes), type, true);
            } catch {
                return LeapTypes.Custom;
            }
        }

        public static string CurieFor(LeapTypes type, LeapFeed feed) {
            return feed.LeapTypesNamespacePrefix + ":" + type.ToString().ToLower();
        }

        public static string UrlFor(LeapTypes type, LeapFeed feed) {
            return feed.LeapTypesNamespace + type.ToString().ToLower();
        }
    }

    /// <summary>
    /// Standard Atom category schemes in LEAP2A, 
    /// details can be found at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories
    /// </summary>
    public static class LeapCategorySchemes {
        public static readonly Dictionary<LeapVersion, string> Namespaces;

        private const string Namespace = "http://wiki.leapspecs.org/2A/categories/";
        public const string NamespacePrefix = "categories";

        public const string LifeArea = "life_area#";
        public const string ResourceType = "resource_type#";
        public const string LearningCycle = "learning_cycle#";
        public const string SelectionType = "selection_type#";
        public const string SWOT = "SWOT#";
        public const string Priority = "priority#";
        public const string CommonItem = "common_item#";
        public const string PersonType = "person_type#";
        public const string Check = "check#";

        static LeapCategorySchemes() {
            Namespaces = new Dictionary<LeapVersion, string>();
            Namespaces.Add(LeapVersion.v2009_03, "http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/");
            Namespaces.Add(LeapVersion.v2010_07, Namespace);
            Namespaces.Add(LeapVersion.Development, Namespace);
        }

        public static bool ContainsNamespace(string value) {
            if (string.IsNullOrEmpty(value)) {
                return false;
            }

            foreach (var ns in Namespaces) {
                if (ns.Value.ToLower() == value.ToLower()) {
                    return true;
                }
            }

            return false;
        }
    }

    /// <summary>
    /// Atom category terms for check box entires in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/check
    /// </summary>
    public static class LeapCheckTerms {
        public const string Yes = "Yes";
        public const string No = "No";
    }

    /// <summary>
    /// Atom category terms for person types in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/person_type
    /// </summary>
    public static class LeapPersonTypeTerms {
        public const string Self = "Self";
        public const string Guardian = "Guardian";
        public const string Referee = "Referee";
        public const string Friend = "Friend";
        public const string Mentor = "Mentor";
        public const string Assessor = "Assessor";
    }

    /// <summary>
    /// Atom category terms for common items types in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/common_item
    /// </summary>
    public static class LeapCommonItemTerms {
        public const string PersonalStatement = "Personalstatement";
        public const string Note = "Note";
    }

    /// <summary>
    /// Atom category terms for the resources in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/resource_type
    /// </summary>
    public static class LeapResourceTypeTerms {
        public const string Book = "Book";
        public const string Web = "Web";
        public const string Human = "Human";
        public const string Course = "Course";
        public const string Offline = "Offline";
        public const string Unclassified = "Unclassified";
        public const string Other = "Other";
        public const string Physical = "Physical";
    }

    /// <summary>
    /// Atom category terms for the Kolb learning cycle in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/learning_cycle
    /// </summary>
    public static class LeapLearningCycleTerms {
        public const string Experiencing = "Experiencing";
        public const string Reflecting = "Reflecting";
        public const string Conceptualizing = "Conceptualizing";
        public const string Testing = "Testing";
    }

    /// <summary>
    /// Atom category terms for priotity in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/priority
    /// </summary>
    public static class LeapPriorityTerms {
        public const string Five = "5";
        public const string Four = "4";
        public const string Three = "3";
        public const string Two = "2";
        public const string One = "1";
    }

    /// <summary>
    /// Life areas included in LEAP2A, 
    /// details can be found at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/life_area
    /// </summary>
    public static class LeapLifeAreaTerms {
        public const string Development = "Development";
        public const string Education = "Education";
        public const string Enterprise = "Enterprise";
        public const string Family = "Family";
        public const string Involuntary = "Involuntary";
        public const string Leisure = "Leisure";
        public const string National = "National";
        public const string Personal = "Personal";
        public const string Placement = "Placement";
        public const string Religion = "Religion";
        public const string Training = "Training";
        public const string Travel = "Travel";
        public const string Voluntary = "Voluntary";
        public const string Work = "Work";
    }

    /// <summary>
    /// Atom category terms for a SWOT analysis in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/SWOT
    /// </summary>
    public static class LeapSwotTerms {
        public const string Strength = "Strength";
        public const string Weakness = "Weakness";
        public const string Opportunity = "Opportunity";
        public const string Threat = "Threat";
    }

    /// <summary>
    /// Atom category terms for selection types in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_categories/selection_type
    /// </summary>
    public static class LeapSelectionTypeTerms {
        public const string CV = "CV";
        public const string Webpage = "Webpage";
        public const string Blog = "Blog";
        public const string Abilities = "Abilities";
        public const string Folder = "Folder";
        public const string Grouping = "Grouping";
        public const string Website = "Website";
    }

    /// <summary>
    /// Shared field terms for personal and organisational data in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_personal_data
    /// and at http://wiki.cetis.ac.uk/2009-03/LEAP2A_organizational_data
    /// </summary>
    public class LeapSharedDataFieldTypes {
        public const string Country = "country";
        public const string Website = "website";
        public const string ID = "id";
        public const string Email = "email";
        public const string WorkPhone = "workphone";
        public const string Minicom = "minicom";
        public const string Fax = "fax";
        public const string Other = "other";
    }

    /// <summary>
    /// Atom category terms for Personal data in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_personal_data
    /// </summary>
    public class LeapPersonalFieldTypes : LeapSharedDataFieldTypes {
        public const string FullName = "full_name";
        public const string LegalFamilyName = "legal_family_name";
        public const string LegalGivenName = "legal_given_name";
        public const string PreferredFamilyName = "preferred_family_name";
        public const string PreferredGivenName = "preferred_given_name";
        public const string NamePrefix = "name_prefix";
        public const string NameSufix = "name_sufix";
        public const string DOB = "dob";
        public const string Gender = "gender";
        public const string HomePhone = "homephone";
        public const string Mobile = "mobile";
    }

    /// <summary>
    /// Atom category terms for Personal data in LEAP2A, 
    /// details at http://wiki.cetis.ac.uk/2009-03/LEAP2A_organizational_data
    /// </summary>
    public class LeapOrganizationalFieldTypes : LeapSharedDataFieldTypes {
        public const string LegalName = "legal_org_name";
        public const string PreferredName = "preferred_org_name";
    }
}
